package cn.com.bluemoon.daps.model.controller;

import cn.com.bluemoon.common.KeyAnnotationClz;
import cn.com.bluemoon.common.UserPermission;
import cn.com.bluemoon.daps.api.sync.RemoteSyncService;
import cn.com.bluemoon.daps.api.sys.RemoteSystemDatasourceService;
import cn.com.bluemoon.daps.common.datascope.BmPermission;
import cn.com.bluemoon.daps.common.datascope.log.OperateLog;
import cn.com.bluemoon.daps.common.datascope.log.enums.ModuleObject;
import cn.com.bluemoon.daps.common.datascope.log.enums.OperateType;
import cn.com.bluemoon.daps.common.domain.BaseModel;
import cn.com.bluemoon.daps.common.domain.ResultBean;
import cn.com.bluemoon.daps.common.domain.UserInfoHolder;
import cn.com.bluemoon.daps.common.enums.BmStatus;
import cn.com.bluemoon.daps.common.enums.DatabaseType;
import cn.com.bluemoon.daps.common.exception.DapThrowException;
import cn.com.bluemoon.daps.common.toolkit.JsonUtil;
import cn.com.bluemoon.daps.model.dto.ChangeHistory;
import cn.com.bluemoon.daps.model.dto.ModifyTableContentDto;
import cn.com.bluemoon.daps.model.entity.DapDataModel;
import cn.com.bluemoon.daps.model.entity.DapDataModelOperateHistory;
import cn.com.bluemoon.daps.model.entity.DapDataModelRecord;
import cn.com.bluemoon.daps.model.service.DapDataModelOperateHistoryService;
import cn.com.bluemoon.daps.model.service.DapDataModelRecordService;
import cn.com.bluemoon.daps.model.service.DapDataModelService;
import cn.com.bluemoon.daps.model.vo.SearchModelApplicationVo;
import cn.com.bluemoon.daps.model.vo.SearchRecordTableVo;
import cn.com.bluemoon.daps.standard.dto.ApplicationModelDto;
import cn.com.bluemoon.daps.sync.vo.applypublish.TableApplyPublishReportVo;
import cn.com.bluemoon.daps.system.dto.DatasourceDto;
import cn.com.bluemoon.daps.system.entity.DapSystemDatasource;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 申请发布审批状态表 前端控制器
 * </p>
 *
 * @author admin
 * @since 2020-08-04
 */
@RestController
@Slf4j
@RequestMapping("/dapDataModelRecord")
@Api(tags = {"模型发布"})
public class DapDataModelRecordController {

    @Resource
    DapDataModelRecordService dapDataModelRecordService;

    @Resource
    DapDataModelOperateHistoryService service;

    @Resource
    DapDataModelService dapDataModelService;

    @Resource
    RemoteSystemDatasourceService remoteSystemDatasourceService;

    @Resource
    private RemoteSyncService remoteSyncService;

    @PostMapping("/release")
    @ApiOperation("申请发布")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Boolean.class)})
    @BmPermission(value = "model:publish", name = "申请发布")
    @UserPermission.SingleRow(keyFormClz = KeyAnnotationClz.RequestParam, key = "modelId", errorMsg = "您没有发布模型的权限")
    @OperateLog(type = OperateType.INSERT, moduleName = ModuleObject.DATA_MODEL)
    public ResultBean<Boolean> applicationRelease(@RequestParam("modelId") @ApiParam("模型id") String modelId,
                                                  @RequestParam("databaseType") @ApiParam("数据库类型") DatabaseType databaseType){
        // 查询模型信息
        DapDataModel dapDataModel = dapDataModelService.getBaseMapper().selectById(modelId);
        String account = UserInfoHolder.getAccount();
        if(!account.equals(dapDataModel.getModelAdmin())){
            return ResultBean.error("只允许模型管理员进行发布");
        }
        // 查询是否具有发布条件
        List<DapDataModelRecord> dapDataModelRecords = dapDataModelRecordService.getBaseMapper().selectList(new LambdaQueryWrapper<DapDataModelRecord>().
                ne(DapDataModelRecord::getPublicStatus, 1).eq(BaseModel::getBmStatus, BmStatus.ON.getCode())
                .eq(DapDataModelRecord::getModelId, modelId));
        if(!dapDataModelRecords.isEmpty()){
            return ResultBean.error("当前模型处于发布流程中，不允许再次发布");
        }
        if(databaseType.equals(DatabaseType.MYSQL)){
            ResultBean<List<TableApplyPublishReportVo>> resultBean = null;
            try {
                resultBean = remoteSyncService.modelTableLayerPredicate(modelId);
            } catch (Exception e){
                log.error("调用同步结构表语法检查失败", e);
                throw new DapThrowException("调用同步结构表语法检查失败", e);
            }
            List<TableApplyPublishReportVo> reportVos = resultBean.getContent();
            if (reportVos != null && !reportVos.isEmpty()){
                return ResultBean.<Boolean>error("模型表存在语法错误！请修正后再申请发布！！").addMoreData("layerInfos", reportVos);
            }
            // 是否开启自动审核
            ResultBean<DatasourceDto> datasourceInfo = remoteSystemDatasourceService.getDatasourceInfo(dapDataModel.getDataSourceId());
            // 同步到生产环境，判断是否存在发布和预发布环境才能进行发布操作
            if(dapDataModel.getIsSyncProd()){
                ResultBean<Boolean> result = remoteSystemDatasourceService.isExistPreAndProEnvironment(dapDataModel.getDataSourceId());
                return result.getCode() == 200 ? dapDataModelRecordService.publishMysqlModel(dapDataModel,datasourceInfo.getContent().getDapSystemDatasource()) : result;
            }
            // 不同步到生产环境，无需判断
            return dapDataModelRecordService.publishMysqlModel(dapDataModel,datasourceInfo.getContent().getDapSystemDatasource());
        }
        return dapDataModelRecordService.publishPgOrHiveModel(modelId, databaseType, dapDataModel.getModelAdmin());
    }

    @PostMapping("/release/list")
    @ApiOperation("申请发布列表")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = ApplicationModelDto.class)})
    @BmPermission(value = "model:publish:list", name = "发布模型")
    public ResultBean<IPage<ApplicationModelDto>> applicationList(@RequestBody @Valid SearchModelApplicationVo application){

        // 查询列表信息
        IPage<ApplicationModelDto> list = dapDataModelRecordService.getList(application,null);
        return ResultBean.ok(list);
    }

    @PostMapping("/verify/list")
    @ApiOperation("审核列表")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = ApplicationModelDto.class)})
    @BmPermission(value = "model:verify:list", name = "审核模型")
    public ResultBean<IPage<ApplicationModelDto>> verifyList(@RequestBody @Valid SearchModelApplicationVo application){

        // 查询列表信息
        IPage<ApplicationModelDto> list = dapDataModelRecordService.getList(application,1);
        return ResultBean.ok(list);
    }

    @PostMapping("/release/modelTable")
    @ApiOperation("查看模型下的表详情信息")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = DapDataModelOperateHistory.class)})
    @BmPermission(value = {"model:verify:info","model:publish:info"}, name = "查看")
    public ResultBean<IPage<DapDataModelOperateHistory>> applicationTableList(@RequestBody @Valid SearchRecordTableVo vo){

        // 获得到修改表记录
        IPage<DapDataModelOperateHistory> tableRecordList = service.getTableRecordList(vo);
        if(tableRecordList.getRecords().isEmpty()){
            return ResultBean.error("页面有缓存，请点击查询刷新页面");
        }
        return ResultBean.ok(tableRecordList);
    }

    @GetMapping("/release/single/sql")
    @ApiOperation("查看申请单下所有变更sql信息")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = DapDataModelOperateHistory.class)})
    @BmPermission(value = {"model:verify:info","model:publish:info"}, name = "查看")
    public ResultBean<List<String>> applicationSingleTable(@RequestParam @NotNull(message = "模型表id不能为空") String recordId){

        // 获得到当前发布所有的sql脚本
        List<DapDataModelOperateHistory> histories = service.getBaseMapper().selectList(new LambdaQueryWrapper<DapDataModelOperateHistory>()
                .eq(DapDataModelOperateHistory::getDataModelRecordId, recordId));
        // 查询数据库类型
        if(histories.isEmpty()){
            return ResultBean.error("页面有缓存，请点击查询刷新页面");
        }
        DapDataModel dapDataModel = dapDataModelService.getBaseMapper().selectById(histories.stream().findFirst().get().getModelId());
        ResultBean<DapSystemDatasource> datasource = remoteSystemDatasourceService.getDatasource(dapDataModel.getDataSourceId());
        DatabaseType databaseType = datasource.getContent().getDatabaseType();
        List<Collection<String>> collect = histories.stream().map(h -> { Map<String, String> map = JsonUtil.jsonStringToMap(h.getPublicContent());
                    return map.values();}).collect(Collectors.toList());
        List<String> sqlScript = collect.stream().collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);
        return ResultBean.ok(sqlScript).addMoreData("databaseType", databaseType);
    }

    @GetMapping("/modify/modelTable")
    @ApiOperation("查看表的详细修改信息")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = ModifyTableContentDto.class)})
    @BmPermission(value = {"model:verify:info","model:publish:info"}, name = "查看")
    public ResultBean<List<ModifyTableContentDto>> tableHistory(@RequestParam @NotNull(message = "模型表id不能为空") String modelTableId,
                                                                @RequestParam(required = false)String applicationTime){

        // 获得到修改表记录
        List<DapDataModelOperateHistory> tableModifyList = service.getTableModifyList(modelTableId, applicationTime);
        List<ModifyTableContentDto> list = new ArrayList<>();
        for (DapDataModelOperateHistory history : tableModifyList) {
            ModifyTableContentDto dto = new ModifyTableContentDto();
            dto.setPublicTime(history.getPublicTime());
            Map<String, String> map = JsonUtil.jsonStringToMap(history.getPublicContent());
            for (Map.Entry<String, String> entry : map.entrySet()) {
                ChangeHistory changeHistory = new ChangeHistory();
                changeHistory.setChangeType(entry.getKey());
                changeHistory.setChangeContent(map.get(entry.getKey()));
                dto.getList().add(changeHistory);
            }
            list.add(dto);
        }
        return ResultBean.ok(list);
    }

    @PostMapping("/model/release")
    @ApiOperation("单个模型申请发布")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Boolean.class)})
    @BmPermission(value = "model:application:publish", name = "申请发布")
    @OperateLog(type = OperateType.UPDATE, moduleName = ModuleObject.DATA_MODEL)
    public ResultBean<Boolean> modelApplicationRelease(@RequestParam @NotNull(message = "申请记录id") String recordId,
                                                       @RequestParam @NotNull(message = "发布描述") String desc
                                                        ){
        return dapDataModelRecordService.singleModelApplicationRelease(recordId, desc);

    }

    @PostMapping("/release/cancel")
    @ApiOperation("撤销")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Boolean.class)})
    @BmPermission(value = "model:publish:cancel", name = "撤销")
    @OperateLog(type = OperateType.UPDATE, moduleName = ModuleObject.DATA_MODEL)
    public ResultBean<Boolean> modelApplicationReleaseCancel(@RequestParam @NotNull(message = "模型id不能为空") String modelId,
                                                             @RequestParam @NotNull(message = "模型id不能为空") String recordId){
        return dapDataModelRecordService.cancelRelease(modelId, recordId);
    }

    @PostMapping("/release/pass")
    @ApiOperation("通过发布")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Boolean.class)})
    @BmPermission(value = "model:verify:pass", name = "通过")
    @OperateLog(type = OperateType.UPDATE, moduleName = ModuleObject.DATA_MODEL)
    public ResultBean<String> modelApplicationReleasePass(@RequestParam @NotNull(message = "模型id不能为空") String modelId,
                                                           @RequestParam @NotNull(message = "发布记录id") String recordId){
        DapDataModel dapDataModel = dapDataModelService.getModelById(modelId);
        ResultBean<DapSystemDatasource> datasource = remoteSystemDatasourceService.getDatasource(dapDataModel.getDataSourceId());
        if(datasource.getCode() == 200){
            // 查询模型信息
            ResultBean<String> pass = dapDataModelRecordService.pass(modelId, recordId, datasource.getContent().getDatabaseType(), true);
            return pass;
        }
        return ResultBean.error("无法获取数据源，发布失败");

    }

    @PostMapping("/release/unPass")
    @ApiOperation("不通过发布")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Boolean.class)})
    @BmPermission(value = "model:verify:unpass", name = "不通过")
    @OperateLog(type = OperateType.UPDATE, moduleName = ModuleObject.DATA_MODEL)
    public ResultBean<Boolean> modelApplicationReleaseUnPass(@RequestParam @NotNull(message = "记录id不能为空") String recordId){

        dapDataModelRecordService.unPass(recordId);
        return ResultBean.ok(true);
    }
}
